package com.wl.lib.widget

import android.content.Context
import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView


// Created by wangliang on 2024/4/26.
class TypedRecyclerAdapter(
    val data: MutableList<in Any> = mutableListOf()
) : RecyclerView.Adapter<BaseViewHolder<*>>() {

    private val classTypeRegistry: MutableMap<Class<*>, Int> = mutableMapOf()
    private val viewHolderFactoryRegistry: MutableMap<Int, TypedViewHolderFactory<*>> =
        mutableMapOf()

    inline fun <reified V : View, reified T> registerViewType(
        crossinline itemLayoutParams: (() -> ViewGroup.LayoutParams),
        crossinline bindAction: (view: V, item: T, pos: Int) -> Unit
    ) {
        registerViewType(T::class.java, object : TypedViewHolderFactory<T> {
            override fun createViewHolder(parent: ViewGroup): BaseViewHolder<T> {
                val itemView =
                    V::class.java.getConstructor(Context::class.java).newInstance(parent.context)
                itemView.layoutParams = itemLayoutParams.invoke()
                return object : BaseViewHolder<T>(itemView) {
                    override fun bind(item: T, position: Int) {
                        bindAction.invoke(itemView as V, item, position)
                    }
                }
            }
        })
    }

    inline fun <reified V : View, reified T> registerViewType(
        crossinline bindAction: (view: V, item: T, pos: Int) -> Unit
    ) {
        registerViewType(T::class.java, object : TypedViewHolderFactory<T> {
            override fun createViewHolder(parent: ViewGroup): BaseViewHolder<T> {
                val itemView =
                    V::class.java.getConstructor(Context::class.java).newInstance(parent.context)
                itemView.layoutParams = ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
                )
                return object : BaseViewHolder<T>(itemView) {
                    override fun bind(item: T, position: Int) {
                        bindAction.invoke(itemView as V, item, position)
                    }
                }
            }
        })
    }

    fun <T> registerViewType(clazz: Class<T>, factory: TypedViewHolderFactory<T>) {
        val id = typeCount
        classTypeRegistry[clazz] = id
        viewHolderFactoryRegistry[id] = factory
    }

    private val typeCount: Int
        get() = viewHolderFactoryRegistry.size

    override fun getItemViewType(position: Int): Int {
        return data.getOrNull(position)?.let {
            var classType: Class<*>? = it.javaClass
            while (classType != Any::class.java && !classTypeRegistry.containsKey(classType)) {
                classType = classType?.superclass
            }
            classTypeRegistry[classType] ?: UNKNOWN_VIEW_TYPE
        } ?: UNKNOWN_VIEW_TYPE
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
        return viewHolderFactoryRegistry[viewType]?.createViewHolder(parent)
            ?: createEmptyViewHolder(parent)
    }

    override fun getItemCount(): Int = data.size

    @Suppress("UNCHECKED_CAST")
    override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
        data.getOrNull(position)?.let {
            (holder as? BaseViewHolder<Any>)?.bind(it, position)
        }
    }

    companion object {

        private const val UNKNOWN_VIEW_TYPE: Int = -1

        private fun createEmptyViewHolder(parent: ViewGroup): BaseViewHolder<Any> {
            return object : BaseViewHolder<Any>(View(parent.context)) {
                override fun bind(item: Any, position: Int) {
                    Log.e("TypedRecyclerAdapter", "Unregistered item type: ${item.javaClass}")
                }
            }
        }
    }
}

abstract class BaseViewHolder<in T>(view: View) : RecyclerView.ViewHolder(view) {
    abstract fun bind(item: T, position: Int)
}

interface TypedViewHolderFactory<in T> {
    fun createViewHolder(parent: ViewGroup): BaseViewHolder<T>
}
